package ua.at.tsvetkov.webservices.parsers;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.http.message.BasicNameValuePair;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import ua.at.tsvetkov.file.IO;
import ua.at.tsvetkov.util.Log;

/**
 * The class for retrieve XML data from web service and parsing this. Used HttpClient for requests.
 * 
 * @author Alexandr Tsvetkov 18.09.2012
 */
public abstract class HttpClientWebParsersXML extends HttpClientWebParsersBase {

	protected static final String	PERHAPS_THERE_ARE_NO_DATA_IN_THE_REQUEST	= "Perhaps there are no data in the request ";
	protected static final String	SAX_EXEPTION_MESSAGE								= "At line 1, column 0: no element found";
	protected static final String	PARSER_CONFIGURATION_EXCEPTION				= "ParserConfigurationException in XML data from ";
	protected static final String	IO_EXCEPTION										= "IOException in XML data from ";
	protected static final String	SAX_EXCEPTION										= "SAXException in XML data from ";
	protected static final String	PARSING_XML											= "Parsing XML: ";

	/**
	 * Parse XML document with given url and your implementation of DefaultHandler.
	 * 
	 * @param urlStr request string
	 * @param saxHandler your implementation of DefaultHandler
	 * @param nameValuePairs 
	 * @return true if success
	 */
	public static boolean parse(String urlStr, DefaultHandler saxHandler, List<BasicNameValuePair> nameValuePairs) {
		return parse(urlStr, saxHandler, null, nameValuePairs);
	}

	/**
	 * Parse XML document with given url and your implementation of DefaultHandler for SAX parsing in separate thread. On finish will be send a message to the handler.
	 * 
	 * @param urlStr request string
	 * @param saxHandler your implementation of DefaultHandler
	 * @param handler your implementation of AbstractWebHandler . Receives an empty message. The message will have a result PARSE_SUCCESS if parsing successful or PARSE_ERROR if failure.
	 * @param nameValuePairs
	 */
	public static void parseInThread(final String urlStr, final DefaultHandler saxHandler, final AbstractWebHandler handler, final List<BasicNameValuePair> nameValuePairs) {
		new Thread(new Runnable() {

			@Override
			public void run() {
				parse(urlStr, saxHandler, handler, nameValuePairs);
			}
		}, PARSING_XML + urlStr).start();
	}

	/**
	 * Parse XML from Internet. Choose how to do it - in a separate thread or not. If AbstractWebHandler is not null parsing will be processed in separate thread and not in thread otherwise.
	 * 
	 * @param urlStr request string
	 * @param saxHandler your implementation of DefaultHandler
	 * @param handler your implementation of AbstractWebHandler . Receives an empty message. The message will have a result PARSE_SUCCESS if parsing successful or PARSE_ERROR if failure.
	 * @param nameValuePairs 
	 * @return result for downloading not in thread. For thread parsing always is true
	 */
	protected static boolean parseOnChoice(String urlStr, DefaultHandler saxHandler, AbstractWebHandler handler, List<BasicNameValuePair> nameValuePairs) {
		if (handler != null) {
			parseInThread(urlStr, saxHandler, handler, nameValuePairs);
			return true;
		} else {
			return parse(urlStr, saxHandler, nameValuePairs);
		}
	}

	/**
	 * Download XML from Internet (or from present file), store to file and parse with DefaultHandler this data.
	 * 
	 * @param urlStr request string
	 * @param saxHandler your implementation of DefaultHandler
	 * @param pathAndFileName filename for store
	 * @param isOverride is need to override
	 * @return true if success
	 */
	public static boolean downloadAndParse(String urlStr, DefaultHandler saxHandler, String pathAndFileName, boolean isOverride) {
		if (IO.downloadFile(urlStr, pathAndFileName, isOverride))
			return readAndParse(urlStr, saxHandler, null, pathAndFileName);
		else
			return false;
	}

	/**
	 * Download XML from Internet (or from present file), store to file and parse with DefaultHandler this data in separate thread. On finish will be send a message to the handler.
	 * 
	 * @param urlStr request string
	 * @param saxHandler your implementation of DefaultHandler
	 * @param handler your implementation of AbstractWebHandler . Receives an empty message. The message will have a result PARSE_SUCCESS if parsing successful or PARSE_ERROR if failure.
	 * @param pathAndFileName filename for store
	 * @param isOverride is need to override
	 */
	public static void downloadAndParseInThread(final String urlStr, final DefaultHandler saxHandler, final AbstractWebHandler handler, final String pathAndFileName, boolean isOverride) {
		if (IO.downloadFile(urlStr, pathAndFileName, isOverride)) {
			new Thread(new Runnable() {

				@Override
				public void run() {
					readAndParse(urlStr, saxHandler, handler, pathAndFileName);
				}

			}, PARSING_XML + urlStr).start();
		}
	}

	/**
	 * Download XML from Internet to the file and parse them. Choose how to do it - in a separate thread or not. If AbstractWebHandler is not null parsing will be processed in separate thread and not
	 * in thread otherwise.
	 * 
	 * @param urlStr request string
	 * @param saxHandler your implementation of DefaultHandler
	 * @param handler your implementation of AbstractWebHandler . Receives an empty message. The message will have a result PARSE_SUCCESS if parsing successful or PARSE_ERROR if failure.
	 * @param pathAndFileName filename for store
	 * @param isRewrite is need to rewrite if file exist.
	 * @return result for downloading not in thread. For thread parsing always is true
	 */
	protected static boolean downloadAndParseOnChoice(String urlStr, DefaultHandler saxHandler, String pathAndFileName, AbstractWebHandler handler, boolean isRewrite) {
		if (handler != null) {
			downloadAndParseInThread(urlStr, saxHandler, handler, pathAndFileName, isRewrite);
			return true;
		} else {
			return downloadAndParse(urlStr, saxHandler, pathAndFileName, isRewrite);
		}
	}

	/**
	 * Parse XML data with your implementation of DefaultHandler for SAX parsing. On finish will be send a message to the handler if handler != null
	 * 
	 * @param urlStr request string
	 * @param saxHandler your implementation of DefaultHandler
	 * @param handler your implementation of AbstractWebHandler . Receives an empty message. The message will have a result PARSE_SUCCESS if parsing successful or PARSE_ERROR if failure.
	 * @param nameValuePairs 
	 */
	private static boolean parse(String urlStr, DefaultHandler saxHandler, AbstractWebHandler handler, List<BasicNameValuePair> nameValuePairs) {
		try {
			InputStream in = getWebInputStream(urlStr, nameValuePairs);
			SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
			parser.parse(in, saxHandler);
			in.close();
			if (handler != null)
				handler.sendSuccessMessage();
			return true;
		} catch (SAXException eSAX) {
			if (eSAX.getMessage().equals(SAX_EXEPTION_MESSAGE))
				Log.w(PERHAPS_THERE_ARE_NO_DATA_IN_THE_REQUEST + urlStr, eSAX);
			else
				Log.w(SAX_EXCEPTION + urlStr, eSAX);
		} catch (IOException eIO) {
			Log.w(IO_EXCEPTION + urlStr, eIO);
		} catch (ParserConfigurationException eParsConf) {
			Log.w(PARSER_CONFIGURATION_EXCEPTION + urlStr, eParsConf);
		}
		if (handler != null)
			handler.sendErrorMessage();
		return false;
	}

	/**
	 * Read XML from downloaded file (from given url) and parse with DefaultHandler. On finish will be send a message to the handler if handler != null.
	 * 
	 * @param urlStr request string.
	 * @param saxHandler your implementation of DefaultHandler.
	 * @param handler your implementation of AbstractWebHandler . Receives an empty message. The message will have a result PARSE_SUCCESS if parsing successful or PARSE_ERROR if failure. Can be null.
	 * @param pathAndFileName filename for store
	 * @param isOverride is need to override
	 */
	private static boolean readAndParse(String urlStr, DefaultHandler saxHandler, AbstractWebHandler handler, String pathAndFileName) {
		try {
			InputStream in = getFileInputStream(pathAndFileName);
			SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
			parser.parse(in, saxHandler);
			in.close();
			if (handler != null)
				handler.sendSuccessMessage();
			return true;
		} catch (SAXException eSAX) {
			if (eSAX.getMessage().equals(SAX_EXEPTION_MESSAGE))
				Log.w(PERHAPS_THERE_ARE_NO_DATA_IN_THE_REQUEST + urlStr, eSAX);
			else
				Log.w(SAX_EXCEPTION + urlStr, eSAX);
		} catch (IOException eIO) {
			Log.w(IO_EXCEPTION + urlStr, eIO);
		} catch (ParserConfigurationException eParsConf) {
			Log.w(PARSER_CONFIGURATION_EXCEPTION + urlStr, eParsConf);
		}
		if (handler != null)
			handler.sendErrorMessage();
		return false;
	}

}
